import JavaInterceptor from "@/helper/JavaInterceptor"
import SourceInterceptor from "@/helper/SourceInterceptor"
import RInterceptor from "@/helper/RInterceptor"
import LayoutInterceptor from "@/helper/LayoutInterceptor"
import OtherInterceptor from "@/helper/OtherInterceptor"
import ApiTableInterceptor from "@/helper/ApiTableInterceptor"

const getName = (c) => {
    return c.packageName + '.' + c.className
}

export default {
    result: null,
    interceptors: [],
    convertToMap(risk) {
      const map = { wildMap: [] }
      risk.forEach(r => {
        if (r.className === '*') {
          map.wildMap.push(r)
        } else {
          if (r.methods) {
            r.methodMap = {}
            r.methods.forEach(m => {
              m.parent = getName(r)
              r.methodMap[m.method] = m
            })
          }

          map[getName(r)] = r
        }
      })

      return map
    },
    loadRisks(changeToMap) {
        const handleRisk = risk => {
          return this.convertToMap(risk)
        }

        if (this.result) {
          return new Promise(resolve => {
            const map = handleRisk(this.result)

            if (changeToMap) resolve(map)
            else resolve(this.result)
          })
        }

        return new Promise((resolve, reject) => {
          Promise.all([import('@/assets/risk-config/android.json'), import('@/assets/risk-config/api.json')])
            .then(values => {
                this.result = this.combineJson(values[0].default, values[1].default)
                const map = handleRisk(this.result)

                if (changeToMap) resolve(map)
                else resolve(this.result)
            }).catch(() => {
                reject()
            })
        })
    },
    combineJson(android, api) {
      const finalList = []
      const apiMap = this.convertToMap(api)
      android.forEach(an => {
        const name = getName(an)
        const ap = apiMap[name]
        if (an.className === '*' || !ap) {
          apiMap[name] = an
        } else {
          if (an.methods) {
            an.methods.forEach(m => {
              if (ap.methodMap) {
                const am = ap.methodMap[m.method]
                if (am) {
                  am.riskLevel = m.riskLevel
                  am.desc = m.desc
                } else {
                  ap.methods.push(m)
                }
              } else {
                if (!ap.methods) ap.methods = []
                ap.methods.push(m)
              }
            })
          }
        }
      })

      for (const key in apiMap) {
        finalList.push(apiMap[key])
      }
      return finalList
    },
    invokeInterceptors(data, method) {
        this.interceptors.forEach(i => {
            if (i[method]) i[method](data)
        })
    },
    handleData(data) {
        this.interceptors.push(JavaInterceptor)
        this.interceptors.push(SourceInterceptor)
        this.interceptors.push(RInterceptor)
        this.interceptors.push(LayoutInterceptor)
        this.interceptors.push(OtherInterceptor)
        this.interceptors.push(ApiTableInterceptor)

        return new Promise(resolve => {
            this.loadRisks(true).then(risks => {
                data.forEach(d => {
                    this.invokeInterceptors(d, 'before')
                    const name = getName(d)
                    let r = risks[name]
                    if (!r) {
                        for (let i = 0; i < risks.wildMap.length; i++) {
                            const wr = risks.wildMap[i]
                            if (d.packageName === wr.packageName) {
                                r = wr
                                break
                            }
                        }
                    }

                    if (r) {
                        if (r.riskLevel === undefined) {
                            if (d.methods && r.methodMap) {
                                d.methods.forEach(m => {
                                    const rm = r.methodMap[m.method.split('(')[0]]
                                    if (rm) {
                                        // console.log(rm)
                                        m.riskLevel = rm.riskLevel
                                        m.desc = rm.desc

                                        if (d.riskLevel === undefined) {
                                            d.riskLevel = m.riskLevel
                                        } else {
                                            d.riskLevel = Math.max(d.riskLevel, m.riskLevel)
                                        }
                                    }
                                })
                            }

                            if ((!d.methods || d.methods.length <= 0) && r.methods) {
                                let highCount = 0
                                let desc = ''
                                r.methods.forEach(m => {
                                    if (m.riskLevel === 3) {
                                        highCount++
                                        desc += m.method + '、'
                                    }
                                })

                                if (highCount === 0) {
                                    d.riskLevel = 0
                                } else if (highCount <= r.methods.length / 3) {
                                    d.riskLevel = 1
                                } else if (highCount >= r.methods.length / 3 * 2) {
                                    d.riskLevel = 3
                                } else {
                                    d.riskLevel = 2
                                }
                                d.desc = desc ? (desc + '等无法替换') : ''
                            }
                        } else {
                            d.riskLevel = r.riskLevel
                            d.desc = r.desc

                            d.methods.forEach(m => {
                                m.riskLevel = r.riskLevel
                                m.desc = r.desc
                            })
                        }
                    }
                    this.invokeInterceptors(d, 'after')
                })

                resolve()
            }).catch(() => {
                resolve()
            })
        })
    }
}
